package com.thingsgrid.device.service.impl;

import com.thingsgrid.device.entity.Device;
import com.thingsgrid.device.entity.Icon;
import com.thingsgrid.device.entity.Link;
import com.thingsgrid.device.entity.Product;
import com.thingsgrid.device.service.TopmService;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
@AllArgsConstructor
public class TopmServiceImpl implements TopmService {
	@Autowired
	private MongoTemplate mongoTemplate;

/**
 * topm图子节点链路信息实体类
 */
	@Data
	class LineStyle{
			Integer width;
			String color;
	}
//接口方法实现
	/**
	 * 获得查询条件所有产品类型
	 */
	@Override
	public List GetProductTypeList() {
		List<Product> productList = QueryAllProductList();
		List<String> productTypeList = GetProductTypeListByproductList(productList);
		//对产品表中的产品类型去重
		List<String> productTypeIdList = StringListDeDuplicate(productTypeList);
		List<Map> list =new ArrayList<>();
		//将每一个产品类型转化为前端下拉框中的value，label格式
		for(String oneProductType : productTypeIdList){
			Map<String, String> map = new HashMap<>();
			map.put("value",oneProductType);
			map.put("label",oneProductType);
			list.add(map);
		}
		return list;
	}
	/**
	 * 获得某一产品类型的产品名列表
	 */
	@Override
	public List GetProductNameList(String productTypeId) {
		List<Product> productList = QueryProductListByProductTypeId(productTypeId);
		List<String> productNameList = GetProductNameListByproductList(productList);
		//由于产品表中产品名称不重复，不需要去重
		List<Map> list = new ArrayList<>();
		//同上，转化为value，label格式
		for (String oneProductName : productNameList){
			Map<String, String> map = new HashMap<>();
			map.put("value",oneProductName);
			map.put("label",oneProductName);
			list.add(map);
		}
		return list;
	}
	/**
	 * 获得某一产品的设备名列表
	 */
	//数量多的话是不是不能用下拉菜单？建议改为输入加相关搜索
	@Override
	public List GetDeviceNameList(String productName) {
		//利用产品名称找到产品ID，再利用产品ID查询设备列表
		Product product = QueryProductByProductName(productName);
		List<Device> deviceList = QueryDeviceListByProductId(product.getProductId());
		List<String> deviceNameList = GetDeviceNameListByDeviceList(deviceList);
		//同上，转化value，label格式
		List<Map> list = new ArrayList<>();
		for (String oneDeviceName : deviceNameList){
			Map<String, String> map = new HashMap<>();
			map.put("value",oneDeviceName);
			map.put("label",oneDeviceName);
			list.add(map);
		}
		return list;
	}
	/**
	 * 获得所有图标
	 */
	//图标定制进入时返回所有图标
	@Override
	public List GetIconList() {
		List<Icon> iconList = QueryAllIconList();
		//前端每个图标值包含图标ID和图标网络地址，state为时候点亮
		List<Map> mapList = new LinkedList<>();
		for (Icon oneIcon : iconList){
			Map<Object, Object> map = new HashMap<>();
			map.put("iconId",oneIcon.getIconId());
			map.put("iconAddress",oneIcon.getIconAddress());
			map.put("state",false);
			mapList.add(map);
		}
		return mapList;
	}
	/**
	 * 新增图标，并保存
	 */
	//新建图标，iconAddress为通过调用李龙飞的filefeign获得
	@Override
	public boolean IconSave(List<String> iconAddressList) {
		for (String iconAddress : iconAddressList){
			Icon icon = new Icon();
			//iconId通过UUID自动生成，没有使用mongodb自己生成的_id，_id为Object格式后续可能会出现问题
			String id = UUID.randomUUID().toString();
			icon.setIconId(id);
			icon.setIconAddress(iconAddress);
			icon.setIconType("");
			//localDate对应ISODate格式，后选用String格式，备用
//			LocalDateTime time = LocalDateTime.now();//LocalDate格式时间生成，对应mongodb中的ISODate
//			icon.setCreateTime(time);
			SimpleDateFormat today = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
			icon.setCreateTime(today.format(new Date()));
			//mongotemplate的保存，更新返回值为实体类，所以使用try判断是否保存成功
			try{
				SaveIcon(icon);
			}catch (Exception e){
				return false;
			}
		}
		return true;
	}
	/**
	 * 更新产品所使用的图标
	 */
	//图标修改，对应应用按钮,根据图标ID，更新产品对应图标
	@Override
	public Integer IconUpdata(String iconId, String productName) {
		Product product = QueryProductByProductName(productName);
		if (iconId.equals(product.getDeviceIcon())){
			//更新图标为默认图标，不予更新，在从controller中进行判断，传给前端
			return 1;
		}else {
			Icon icon = QueryIconByIconId(iconId);
			//只有当更新图标对应产品为空时进行更新，不存在多个产品对应一个图标，出现返回2
			//若可以需要字符串拼接
			if (icon.getIconType() == null || icon.getIconType().equals("")) {
				boolean isDel = DelIconType(product.getProductId());
				//判断是否删除原图标中的产品ID，并更新成功，不成功返回3，成功返回4
				if(isDel){
					if(UpdateIconTypeByIconId(iconId, product.getProductId())){
						return 4;
					}else {
						return 3;
					}
				}else{
					return 3;
				}
			} else {
				return 2;
			}
		}
	}
	/**
	 * 获得产品对应的链路及默认链路
	 */
	//默认链路信息为deviceLinkWideth和deviceLinkColor，width和color为当前链路信息
	@Override
	public Map QueryDeviceLinkList(String productName) {
		Product product = QueryProductByProductName(productName);
		Map<String, Object> map = new HashMap<>();
		//根据产品名返回默认链路信息，deviceLinkWideth和deviceLinkColor，找到产品ID
		map.put("deviceLinkWideth",product.getDeviceLinkStrong());
		map.put("deviceLinkColor",product.getDeviceLinkColor());
		//根据产品ID查询对应链路表，如不存在，返回默认链路信息
		Link link = QueryLinkByLinkType(product.getProductId());
		if(link == null){
			map.put("width",product.getDeviceLinkStrong());
			map.put("color",product.getDeviceLinkColor());
		}else {
			map.put("width",link.getLinkStrong());
			map.put("color",link.getLinkColor());
		}
		return map;
	}
	/**
	 * 更新产品链路
	 */
	@Override
	public boolean LinkUpdata(Integer linkStrong, String productName, String linkColor) {//链路修改，对应应用按钮
		Product product = QueryProductByProductName(productName);
		Link link = QueryLinkByLinkType(product.getProductId());
		//判断链路表中是否存在该产品的信息，存在更新，不存在新增，是不是可以直接用upsert解决，未尝试
		if (link == null){
			return LinkSave(linkStrong, product.getProductId(),linkColor);
		}else {
			return UpdateLink(linkStrong, product.getProductId(),linkColor);
		}
	}

	/**
	 *链路表中不存在该产品时，保存新链路
	 */
	private boolean LinkSave(Integer linkStrong, String linkType, String linkColor){
		Link link = new Link();
		String id = UUID.randomUUID().toString();
		link.setLinkId(id);
		link.setLinkStrong(linkStrong);
		link.setLinkColor(linkColor);
		link.setLinkType(linkType);
		SimpleDateFormat today = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
		link.setCreateTime(today.format(new Date()));
		return SaveLink(link);
	}
	/**
	 * 根据查询条件获得拓扑图信息
	 * 拓扑图显示包括那些信息
	 */
	//由于拓扑图中包括产品，设备，图标，链路四个表，没有使用聚合查询，
	//做了存在查询条件为空时的查询，如前端增加该功能可直接使用
	@Override
	public List<Map> QueryTopmByConsition(String productTypeId, String productName, String deviceName) {
		List<Map> topmList = new LinkedList<>();

		if ((productTypeId == null || productTypeId.equals("")) &&
			(productName == null || productName.equals("")) &&
			(deviceName == null || deviceName.equals(""))) {
			//拓扑图中节点信息如果需要减少可以在下一列的查询中进行修改，增加field，共四处
			List<Device> parentDeviceList = QueryAllParentDeviceList();
			//以下为将设备列表转化为前端拓扑图的格式，name为名称，symbol为图标地址，
			// Info为鼠标停留时显示的信息，children为对应子节点列
			for (Device oneParentDevice : parentDeviceList){
				Map<String, Object> topmTree = new HashMap<>();
				topmTree.put("name",oneParentDevice.getDeviceName());
				Icon icon = QueryIconByIconType(oneParentDevice.getProductId());
				if (icon == null){
					Product product = QueryProductByProductId(oneParentDevice.getProductId());
					icon = QueryIconByIconId(product.getDeviceIcon());
					topmTree.put("symbol",icon.getIconAddress());
				}else{
					topmTree.put("symbol",icon.getIconAddress());
				}
				Map nodemap = new LinkedHashMap();
				nodemap.put("名称",oneParentDevice.getDeviceName());
				nodemap.put("标识",oneParentDevice.getDeviceId());
				nodemap.put("制造商",oneParentDevice.getDeviceFirm());
				nodemap.put("纬度",oneParentDevice.getDimension());
				nodemap.put("经度",oneParentDevice.getLongitude());
				nodemap.put("IP地址",oneParentDevice.getIpAddress());
				nodemap.put("型号",oneParentDevice.getDeviceType());
				topmTree.put("info",nodemap);
				List<Device> childDeviceList = QueryChildDeviceListByParentDeviceId(oneParentDevice.getDeviceId());
				List<Map> topmNodeList = GetTopmNodeList(childDeviceList);
				topmTree.put("children",topmNodeList);
				topmList.add(topmTree);
			}
		}else if (!(deviceName == null || deviceName.equals(""))){
			//拓扑图中节点信息如果需要减少可以在下一列的查询中进行修改，增加field
			Device device = QueryDeviceByDeviceName(deviceName);
			if (!(device.getParentDeviceId() == null ||device.getParentDeviceId().equals(""))){
				device = QueryDeviceByDeviceId(device.getParentDeviceId());
			}
			Map<String, Object> topmTree = new HashMap<>();
			topmTree.put("name",device.getDeviceName());
			Icon icon = QueryIconByIconType(device.getProductId());
			if (icon == null){
				Product product = QueryProductByProductId(device.getProductId());
				icon = QueryIconByIconId(product.getDeviceIcon());
				topmTree.put("symbol",icon.getIconAddress());
			}else{
				topmTree.put("symbol",icon.getIconAddress());
			}
			Map nodemap = new LinkedHashMap();
			nodemap.put("名称",device.getDeviceName());
			nodemap.put("标识",device.getDeviceId());
			nodemap.put("制造商",device.getDeviceFirm());
			nodemap.put("纬度",device.getDimension());
			nodemap.put("经度",device.getLongitude());
			nodemap.put("IP地址",device.getIpAddress());
			nodemap.put("型号",device.getDeviceType());
			topmTree.put("info",nodemap);
			List<Device> childDeviceList = QueryChildDeviceListByParentDeviceId(device.getDeviceId());
			List<Map> topmNodeList = GetTopmNodeList(childDeviceList);
			topmTree.put("children",topmNodeList);
			topmList.add(topmTree);
		}else if (!(productName == null || productName.equals(""))) {
			Product product = QueryProductByProductName(productName);
			//拓扑图中节点信息如果需要减少可以在下一列的查询中进行修改，增加field
			List<Device> deviceList = QueryDeviceListByProductId(product.getProductId());
			for (Device oneDevice : deviceList){
				if (!(oneDevice.getParentDeviceId() == null || oneDevice.getParentDeviceId().equals(""))){
					oneDevice = QueryDeviceByDeviceId(oneDevice.getParentDeviceId());
				}
				Map<String, Object> topmTree = new HashMap<>();
				topmTree.put("name",oneDevice.getDeviceName());
				Icon icon = QueryIconByIconType(oneDevice.getProductId());
				if (icon == null){
					product = QueryProductByProductId(oneDevice.getProductId());
					icon = QueryIconByIconId(product.getDeviceIcon());
					topmTree.put("symbol",icon.getIconAddress());
				}else{
					topmTree.put("symbol",icon.getIconAddress());
				}
				Map nodemap = new LinkedHashMap();
				nodemap.put("名称",oneDevice.getDeviceName());
				nodemap.put("标识",oneDevice.getDeviceId());
				nodemap.put("制造商",oneDevice.getDeviceFirm());
				nodemap.put("纬度",oneDevice.getDimension());
				nodemap.put("经度",oneDevice.getLongitude());
				nodemap.put("IP地址",oneDevice.getIpAddress());
				nodemap.put("型号",oneDevice.getDeviceType());
				topmTree.put("info",nodemap);
				List<Device> childDeviceList = QueryChildDeviceListByParentDeviceId(oneDevice.getDeviceId());
				List<Map> topmNodeList = GetTopmNodeList(childDeviceList);
				topmTree.put("children",topmNodeList);
				topmList.add(topmTree);
			}
		}else {
			List<Product> productList = QueryProductListByProductTypeId(productTypeId);
			for (Product oneProduct : productList){
				//拓扑图中节点信息如果需要减少可以在下一列的查询中进行修改，增加field
				List<Device> deviceList = QueryDeviceListByProductId(oneProduct.getProductId());
				for (Device oneDevice : deviceList){
					if (!(oneDevice.getParentDeviceId() == null || oneDevice.getParentDeviceId().equals(""))){
						oneDevice = QueryDeviceByDeviceId(oneDevice.getParentDeviceId());
					}
					Map<String, Object> topmTree = new HashMap<>();
					topmTree.put("name",oneDevice.getDeviceName());
					Icon icon = QueryIconByIconType(oneDevice.getProductId());
					if (icon == null){
						Product product = QueryProductByProductId(oneDevice.getProductId());
						icon = QueryIconByIconId(product.getDeviceIcon());
						topmTree.put("symbol",icon.getIconAddress());
					}else{
						topmTree.put("symbol",icon.getIconAddress());
					}
					Map nodemap = new LinkedHashMap();
					nodemap.put("名称",oneDevice.getDeviceName());
					nodemap.put("标识",oneDevice.getDeviceId());
					nodemap.put("制造商",oneDevice.getDeviceFirm());
					nodemap.put("纬度",oneDevice.getDimension());
					nodemap.put("经度",oneDevice.getLongitude());
					nodemap.put("IP地址",oneDevice.getIpAddress());
					nodemap.put("型号",oneDevice.getDeviceType());
					topmTree.put("info",nodemap);
					List<Device> childDeviceList = QueryChildDeviceListByParentDeviceId(oneDevice.getDeviceId());
					List<Map> topmNodeList = GetTopmNodeList(childDeviceList);
					topmTree.put("children",topmNodeList);
					topmList.add(topmTree);
				}
			}
		}
		return ListDeDuplicate(topmList);
	}

	/**
	 * 根据子节点列表生成对应的拓扑图格式
	 */
	//子节点信息比母节点多两个链路信息，所以单独处理
	private List<Map> GetTopmNodeList(List<Device> deviceList){
		List<Map> nodeMapList= new ArrayList<>();
		for (Device oneDevice : deviceList){
			Map<String, Object> nodeMap = new HashMap<>();
			nodeMap.put("name", oneDevice.getDeviceName());
			Icon icon = QueryIconByIconType(oneDevice.getProductId());
			if (icon == null){
				Product product = QueryProductByProductId(oneDevice.getProductId());
				icon = QueryIconByIconId(product.getDeviceIcon());
				nodeMap.put("symbol",icon.getIconAddress());
			}else{
				nodeMap.put("symbol",icon.getIconAddress());
			}
			Link link = QueryLinkByLinkType(oneDevice.getProductId());
			LineStyle lineStyle = new LineStyle();
			if (link == null){
				Product product = QueryProductByProductId(oneDevice.getProductId());
				lineStyle.setWidth(product.getDeviceLinkStrong());
				lineStyle.setColor(product.getDeviceLinkColor());
			}else{
				lineStyle.setWidth(link.getLinkStrong());
				lineStyle.setColor(link.getLinkColor());
			}
			nodeMap.put("lineStyle",lineStyle);
			Map nodemap = new LinkedHashMap();
			nodemap.put("名称",oneDevice.getDeviceName());
			nodemap.put("标识",oneDevice.getDeviceId());
			nodemap.put("制造商",oneDevice.getDeviceFirm());
			nodemap.put("纬度",oneDevice.getDimension());
			nodemap.put("经度",oneDevice.getLongitude());
			nodemap.put("IP地址",oneDevice.getIpAddress());
			nodemap.put("型号",oneDevice.getDeviceType());
			nodeMap.put("info",nodemap);
			nodeMapList.add(nodeMap);
		}
		return nodeMapList;
	}
	/**
	 * 获得产品对应的图标及默认图标
	 */
	//和链路相同，deviceIcon为默认图标icon为当前使用图标
	@Override
	public Map QueryDeviceIconList(String productName){
		Product product = QueryProductByProductName(productName);
		Map<String, String> map = new HashMap<>();
		map.put("deviceIcon", product.getDeviceIcon());
		Icon icon = QueryIconByIconType(product.getProductId());
		if (icon == null){
			map.put("icon",product.getDeviceIcon());
		}else{
			map.put("icon",icon.getIconId());
		}
		return map;
	}
	/**
	 * 获得所有产品名
	 */
	@Override
	public List GetAllProductNameList(){
		List<Product> productList = QueryAllProductList();
		List<String> productNameList = GetProductNameListByproductList(productList);
		List<Map> mapList = new ArrayList<>();
		for (String oneProductName : productNameList){
			Map<String, String> map = new HashMap<>();
			map.put("value",oneProductName);
			map.put("label",oneProductName);
			mapList.add(map);
		}
		return mapList;
	}

	//以下为查询语句

	/**
	 *查询语句Query后为查询内容，有list是返回列表，无list返回单个对象
	 * Save和Update使用try判断是否存储成功，返回boolean
	 */
	private Device QueryDeviceByDeviceName(String deviceName) {
		Criteria criteria = new Criteria();
		criteria.and("deviceName").is(deviceName);
		criteria.and("stats").is(1);
		criteria.and("start_stats").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.findOne(query, Device.class, "device");
	}

	private List<Device> QueryChildDeviceListByParentDeviceId(String parentDeviceId) {
		Criteria criteria = new Criteria();
		criteria.and("parentDeviceId").is(parentDeviceId);
		criteria.and("stats").is(1);
		criteria.and("start_stats").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.find(query, Device.class, "device");
	}

	private List<Product> QueryProductListByProductTypeId(String productTypeId) {
		Criteria criteria = new Criteria();
		criteria.and("productTypeId").is(productTypeId);
		criteria.and("is_publish").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.find(query, Product.class, "product");
	}

	private Product QueryProductByProductId(String productId){
		Criteria criteria = new Criteria();
		criteria.and("productId").is(productId);
		criteria.and("is_publish").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.findOne(query, Product.class, "product");
	}

	private Icon QueryIconByIconType(String iconType) {
		Query query = new Query(Criteria.where("iconType").is(iconType));
		return mongoTemplate.findOne(query, Icon.class, "icon");
	}

	private List<Icon> QueryAllIconList() {
		return mongoTemplate.findAll(Icon.class,"icon");
	}

	private void SaveIcon(Icon icon) {//返回类型
		mongoTemplate.insert(icon, "icon");//insert返回值是什么，抛出异常-重复
	}

	private Icon QueryIconByIconId(String iconId) {
		Query query = new Query(Criteria.where("iconId").is(iconId));
		return mongoTemplate.findOne(query, Icon.class, "icon");
	}

	private boolean DelIconType(String iconType) {
		Query query = new Query(Criteria.where("iconType").is(iconType));
		Update update = Update.update("iconType", "");//将数据库中iconType赋null，是否能转为删除Field？
		try {
			mongoTemplate.updateFirst(query, update, Icon.class);
		}catch (Exception e){
			return false;
		}
		return true;
	}

	private boolean UpdateIconTypeByIconId(String iconId, String iconType) {
		Query query = new Query(Criteria.where("iconId").is(iconId));
		Update update = Update.update("iconType", iconType);
		try {
			mongoTemplate.updateFirst(query, update, Icon.class);
		}catch (Exception e){
			return false;
		}
		return true;
	}

	private Link QueryLinkByLinkType(String linkType) {
		Query query = new Query(Criteria.where("linkType").is(linkType));
		return mongoTemplate.findOne(query, Link.class, "link");
	}

	private boolean SaveLink(Link link){
		mongoTemplate.insert(link, "link");//insert返回值是什么，抛出异常-重复
		return true;
	}
	private boolean UpdateLink(Integer linkStrong, String linkType, String linkColor) {
		Query query = new Query(Criteria.where("linkType").is(linkType));
		Update update = new Update();
		update.set("linkStrong", linkStrong);
		update.set("linkColor", linkColor);
		try {
			mongoTemplate.updateFirst(query, update, Link.class,"link");
		}catch (Exception e){
			return false;
		}
		return true;
	}

	private Product QueryProductByProductName(String productName) {
		Criteria criteria = new Criteria();
		criteria.and("product_name").is(productName);
		criteria.and("is_publish").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.findOne(query, Product.class, "product");
	}

	private List<Device> QueryDeviceListByProductId(String productId) {
		Criteria criteria = new Criteria();
		criteria.and("productId").is(productId);
		criteria.and("stats").is(1);
		criteria.and("start_stats").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.find(query, Device.class, "device");
	}
	private List<Device> QueryAllParentDeviceList() {
		Criteria criteria = new Criteria();
		criteria.and("parentDeviceId").is(null);
		criteria.and("stats").is(1);
		criteria.and("start_stats").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.find(query, Device.class, "device");
	}
	private Device QueryDeviceByDeviceId(String devicrId){
		Criteria criteria = new Criteria();
		criteria.and("deviceId").is(devicrId);
		criteria.and("stats").is(1);
		criteria.and("start_stats").is(1);
		Query query = new Query(criteria);
		return mongoTemplate.findOne(query, Device.class, "device");
	}

	private List<String> GetDeviceNameListByDeviceList(List<Device> deviceList) {
		List<String> deviceNameList = new ArrayList<>();
		for (Device oneDevice : deviceList) {
			String deviceName = oneDevice.getDeviceName();
			deviceNameList.add(deviceName);
		}
		return deviceNameList;
	}


	private List<Product> QueryAllProductList() {
		Query query = new Query(Criteria.where("is_publish").is(1));
		return mongoTemplate.find(query, Product.class, "product");
	}

	private List<String> GetProductTypeListByproductList(List<Product> productList) {
		List<String> productTypeList = new ArrayList<>();
		for (Product product : productList) {
			productTypeList.add(product.getProductTypeId());
		}
		return productTypeList;
	}

	private List<String> GetProductNameListByproductList(List<Product> productList) {
		List<String> productNameList = new ArrayList<>();
		for (Product product : productList) {
			productNameList.add(product.getProductName());
		}
		return productNameList;
	}

	/**
	 *以下两个为list去重，分别对应List<Map>和List<String>
	 */
	private List<Map> ListDeDuplicate(List<Map> oneList) {
		HashSet<Map> h = new HashSet<>(oneList);
		oneList.clear();
		oneList.addAll(h);
		return oneList;
	}
	private List<String> StringListDeDuplicate(List<String> oneList) {
		HashSet<String> h = new HashSet<>(oneList);
		oneList.clear();
		oneList.addAll(h);
		return oneList;
	}

}
